home *** CD-ROM | disk | FTP | other *** search
/ EnigmA Amiga Run 1999 March / EnigmA AMIGA RUN 35 (1999)(G.R. Edizioni)(IT)[!][issue 1999-03].iso / earcd / grafica / amhelios / parse.cpp < prev    next >
C/C++ Source or Header  |  1999-01-01  |  15KB  |  605 lines

  1. ////////////////////////////////////////////////////////////
  2. //
  3. //  PARSE.CPP - Environment Data File Parser Class
  4. //
  5. //  Version:    1.03A
  6. //
  7. //  History:    94/08/23 - Version 1.00A release.
  8. //              94/12/16 - Version 1.01A release.
  9. //              95/02/05 - Version 1.02A release.
  10. //              95/07/14 - Added /Ow optimization pragma for
  11. //                         ReadSurface function (compiler
  12. //                         bug workaround).
  13. //              95/07/21 - Version 1.02B release.
  14. //              96/02/14 - Version 1.02C release.
  15. //              96/02/27 - Modified ParseFile to calculate
  16. //                         environment extents.
  17. //              96/04/01 - Version 1.03A release.
  18. //
  19. //  Compilers:  Microsoft Visual C/C++ Professional V1.5
  20. //              Borland C++ Version 4.5
  21. //
  22. //  Author:     Ian Ashdown, P.Eng.
  23. //              byHeart Software Limited
  24. //              620 Ballantree Road
  25. //              West Vancouver, B.C.
  26. //              Canada V7S 1W3
  27. //              Tel. (604) 922-6148
  28. //              Fax. (604) 987-7621
  29. //
  30. //  Copyright 1994-1996 byHeart Software Limited
  31. //
  32. //  The following source code has been derived from:
  33. //
  34. //    Ashdown, I. 1994. Radiosity: A Programmer's
  35. //    Perspective. New York, NY: John Wiley & Sons.
  36. //
  37. //  It may be freely copied, redistributed, and/or modified
  38. //  for personal use ONLY, as long as the copyright notice
  39. //  is included with all source code files.
  40. //
  41. ////////////////////////////////////////////////////////////
  42.  
  43. #include <string.h>
  44. #include "error.h"
  45. #include "parse.h"
  46.  
  47. // File path separator (MS-DOS specific)
  48. static const char PathSeparator[] = "/";
  49.  
  50. // Data file keywords
  51. static const char EndFileStr[] = "END_FILE";
  52. static const char CommentStr[] = "COMMENT";
  53.  
  54. // Parse world file
  55. BOOL Parse::ParseFile( char *fname, char *fpath, Environ
  56.     *pe )
  57. {
  58.   char *pefp;           // Entity file path pointer
  59.   Instance *pinst;      // Instance pointer
  60.   Instance *pinsthd;    // Instance list head pointer
  61.  
  62.   penv = pe;    // Save environment pointer
  63.  
  64.   // Delete previous environment (if any)
  65.   penv->DeleteEnv();
  66.  
  67.   pinst = pinsthd = NULL;
  68.  
  69.   // Initialize environment statistics
  70.   penv->num_inst = (WORD) 0;
  71.   penv->num_surf = (WORD) 0;
  72.   penv->num_patch = (WORD) 0;
  73.   penv->num_elem = (WORD) 0;
  74.   penv->num_vert = (WORD) 0;
  75.  
  76.   // Build file path string
  77.   pefp = ent_buff;
  78.   if (*fpath != '\0')
  79.   {
  80.     strcpy(ent_buff, fpath);
  81.     if (fpath[strlen(ent_buff) - 1] != *PathSeparator)
  82.       strcat(ent_buff, PathSeparator);
  83.     pefp += strlen(ent_buff);
  84.   }
  85.  
  86.   if (ifile.Open(fname) != TRUE)    // Open instance file
  87.   {
  88.     sprintf(msg_buff, "Could not open world file %s",
  89.         fname);
  90.     ReportError(msg_buff);
  91.     return FALSE;
  92.   }
  93.  
  94.   ReadLine(ifile);      // Read world name
  95.  
  96.   for ( ; ; )
  97.   {
  98.     ReadLine(ifile);    // Read entity file name
  99.  
  100.     // Check for end of file
  101.     if (strcmp(line_buff, EndFileStr) == 0)
  102.       break;
  103.  
  104.     // Build full entity file name
  105.     strcpy(pefp, line_buff);
  106.  
  107.     // Read entity file
  108.     if ((pinst = ParseEntityFile()) == NULL)
  109.     {
  110.       ifile.Close();
  111.       return FALSE;
  112.     }
  113.  
  114.     // Read 3-D transformation matrix
  115.     ReadTransform();
  116.  
  117.     // Transform entity into instance
  118.     TransformInstance(pinst);
  119.  
  120.     // Link instance to instance list
  121.     pinst->SetNext(pinsthd);
  122.     pinsthd = pinst;
  123.     penv->num_inst++;
  124.   }
  125.  
  126.   ifile.Close();
  127.   penv->pinsthd = pinsthd;
  128.  
  129.   penv->CalcExtents();  // Calculate environment extents
  130.  
  131.   return TRUE;
  132. }
  133.  
  134. // Parse entity data file
  135. Instance *Parse::ParseEntityFile()
  136. {
  137.   BOOL status;              // Return status
  138.   Instance *pinst;          // Instance pointer
  139.   Surface3 *ps;             // Surface pointer
  140.   Vertex3 *pv;              // Vertex pointer
  141.  
  142.   pinst = NULL;
  143.   ps = NULL;
  144.   pv = NULL;
  145.  
  146.   surf_cnt = patch_cnt = elem_cnt = vert_cnt = (WORD) 0;
  147.  
  148.   // Open entity file
  149.   if (efile.Open(ent_buff) != TRUE)
  150.   {
  151.     sprintf(msg_buff, "Could not open entity file %s",
  152.         ent_buff);
  153.     ReportError(msg_buff);
  154.     return NULL;
  155.   }
  156.  
  157.   ReadLine(efile);      // Read file description
  158.  
  159.   pv = ParseVertices();
  160.   ps = ParseSurfaces();
  161.   status = ParsePatches();
  162.  
  163.   if (status == TRUE)
  164.     status = ParseElements();
  165.  
  166.   // Delete temporary pointer arrays
  167.   delete [] pv_array;
  168.   delete [] ps_array;
  169.   delete [] pp_array;
  170.  
  171.   // Create new entity
  172.   if (status == TRUE)
  173.     pinst = new Instance(pv, ps);
  174.  
  175.   efile.Close();
  176.   return pinst;
  177. }
  178.  
  179. // Parse vertices
  180. Vertex3 *Parse::ParseVertices()
  181. {
  182.   WORD v_index;             // Vertex pointer array index
  183.   Vertex3 *pv;              // Vertex pointer
  184.   Vertex3 *pvhd;            // Vertex list head ptr
  185.  
  186.   pv = pvhd = NULL;
  187.  
  188.   ReadLine(efile);      // Read vertex section header
  189.  
  190.   // Build vertex linked list
  191.   for ( ; ; )
  192.   {
  193.     // Read vertex vector
  194.     if ((pv = ReadVertex()) == NULL)
  195.       break;
  196.  
  197.     // Link vertex to vertex list
  198.     pv->SetNext(pvhd);
  199.     pvhd = pv;
  200.     penv->num_vert++;
  201.     vert_cnt++;
  202.   }
  203.  
  204.   // Build vertex pointer array
  205.   pv = pvhd;
  206.   pv_array = new VertexPtr[vert_cnt];
  207.   v_index = (WORD)(vert_cnt - (WORD) 1);
  208.   while (pv != NULL)
  209.   {
  210.     pv_array[v_index--] = pv;
  211.     pv = pv->GetNext();
  212.   }
  213.   return pvhd;
  214. }
  215.  
  216. // Parse surfaces
  217. Surface3 *Parse::ParseSurfaces()
  218. {
  219.   WORD s_index;             // Surface pointer array index
  220.   Surface3 *ps;             // Surface pointer
  221.   Surface3 *pshd;           // Surface list head ptr
  222.  
  223.   ps = pshd = NULL;
  224.  
  225.   ReadLine(efile);      // Read surface section header
  226.  
  227.   // Build surface linked list
  228.   for ( ; ; )
  229.   {
  230.     // Read surface identifier
  231.     if ((ps = ReadSurface()) == NULL)
  232.       break;
  233.  
  234.     // Link surface to surface list
  235.     ps->SetNext(pshd);
  236.     pshd = ps;
  237.     penv->num_surf++;
  238.     surf_cnt++;
  239.   }
  240.  
  241.   // Build surface pointer array
  242.   ps = pshd;
  243.   ps_array = new SurfacePtr[surf_cnt];
  244.   s_index = (WORD)(surf_cnt - (WORD) 1);
  245.   while (ps != NULL)
  246.   {
  247.     ps_array[s_index--] = ps;
  248.     ps = ps->GetNext();
  249.   }
  250.   return pshd;
  251. }
  252.  
  253. // NOTE: The Microsoft Visual C++ Version 1.5 compiler
  254. //       generates no code for the statement:
  255. //
  256. //         emit.SetBlueBand(eblue);
  257. //
  258. //       in the following function when the /O2 option
  259. //       (Generate Fast Code) is specified unless aliasing
  260. //       across function calls is assumed.
  261.  
  262. #pragma optimize( "w", on )
  263.  
  264. // Read surface identifier
  265. Surface3 *Parse::ReadSurface()
  266. {
  267.   char start[2], end[2];        // Vector separators
  268.   float ered, egreen, eblue;    // Exitance components
  269.   float rred, rgreen, rblue;    // Reflectance components
  270.   Spectra reflect;              // Spectral reflectance
  271.   Spectra emit;                 // Spectral radiant exitance
  272.  
  273.   ReadLine(efile);      // Read color vector
  274.  
  275.   if (sscanf(line_buff, "%1s %f %f %f %1s %1s %f %f %f %1s",
  276.       start, &rred, &rgreen, &rblue, end, start, &ered,
  277.       &egreen, &eblue, end) == 10)
  278.   {
  279.     // Set reflectance
  280.     reflect.SetRedBand(rred);
  281.     reflect.SetGreenBand(rgreen);
  282.     reflect.SetBlueBand(rblue);
  283.  
  284.     // Set initial spectral radiant exitance
  285.     emit.SetRedBand(ered);
  286.     emit.SetGreenBand(egreen);
  287.     emit.SetBlueBand(eblue);
  288.  
  289.     return new Surface3(reflect, emit);
  290.   }
  291.   else
  292.     return NULL;        // Must be terminator
  293. }
  294.  
  295. #pragma optimize( "w", off )
  296.  
  297. // Parse patch identifiers
  298. BOOL Parse::ParsePatches()
  299. {
  300.   char start[2], end[2];    // List separators
  301.   int v_index;              // Vertex pointer array index
  302.   BOOL status = TRUE;       // Status flag
  303.   WORD p_index;             // Patch pointer array index
  304.   WORD s_index;             // Surface index
  305.   WORD ivtx[4];             // Vertex indices
  306.   Patch3 *pp;               // Patch pointer
  307.   Patch3 *pphd;             // Patch head pointer
  308.   PatchList *ppl = NULL;    // Patch list pointer
  309.   PatchList *pplnext;       // Next patch list pointer
  310.   Vertex3 *pv[4];           // Vertex pointers array
  311.  
  312.   ReadLine(efile);      // Read patch section header
  313.  
  314.   for ( ; ; )
  315.  
  316.  
  317.   {
  318.     ReadLine(efile);    // Read patch identifier
  319.  
  320.     if (sscanf(line_buff, "%hd %1s %hd %hd %hd %hd %1s",
  321.         &s_index, start, &ivtx[0], &ivtx[1], &ivtx[2],
  322.         &ivtx[3], end) == 7)
  323.     {
  324.       // Validate surface index
  325.       if (s_index >= surf_cnt)
  326.       {
  327.         sprintf(msg_buff,
  328.             "Entity file: %s\nPatch # %u\nSurface index "
  329.             "error: %s", ent_buff, patch_cnt + 1,
  330.             line_buff);
  331.         ReportError(msg_buff);
  332.         status = FALSE;
  333.         break;
  334.       }
  335.  
  336.       // Validate vertex array indices
  337.       for (v_index = 0; v_index < 4; v_index++)
  338.       {
  339.         if (ivtx[v_index] >= vert_cnt)
  340.         {
  341.           sprintf(msg_buff,
  342.               "Entity file: %s\nPatch # %u\nVertex index "
  343.               "error: %s", ent_buff, patch_cnt + 1,
  344.               line_buff);
  345.           ReportError(msg_buff);
  346.           status = FALSE;
  347.           break;
  348.         }
  349.       }
  350.  
  351.       if (status == FALSE)
  352.         break;
  353.  
  354.       // Get vertex pointers
  355.       for (v_index = 0; v_index < 4; v_index++)
  356.         pv[v_index] = pv_array[ivtx[v_index]];
  357.  
  358.       // Update surface patch linked list
  359.       pp = new Patch3(pv, ps_array[s_index]);
  360.       pphd = ps_array[s_index]->GetPatchPtr();
  361.       pp->SetNext(pphd);
  362.       ps_array[s_index]->SetPatchPtr(pp);
  363.  
  364.       // Determine whether triangle or quadrilateral
  365.       if (ivtx[2] != ivtx[3])
  366.         pp->SetQuad();
  367.     }
  368.     else
  369.       break;
  370.  
  371.     // Link patch to temporary patch list
  372.     ppl = new PatchList(pp, ppl);
  373.     penv->num_patch++;
  374.     patch_cnt++;
  375.   }
  376.  
  377.   // Build patch pointer array and delete patch list
  378.   pp_array = new PatchPtr[patch_cnt];
  379.   p_index = (WORD)(patch_cnt - (WORD) 1);
  380.   while (ppl != NULL)
  381.   {
  382.     pp_array[p_index--] = ppl->GetPatchPtr();
  383.     pplnext = ppl->GetNext();
  384.     delete ppl;
  385.     ppl = pplnext;
  386.   }
  387.  
  388.   return status;
  389. }
  390.  
  391. // Parse element identifiers
  392. BOOL Parse::ParseElements()
  393. {
  394.   char start[2], end[2];    // List separators
  395.   int nvert;                // Number of vertices
  396.   int v_index;              // Vertex pointer array index
  397.   BOOL status = TRUE;       // Status flag
  398.   WORD p_index;             // Patch array index
  399.   WORD ivtx[4];             // Vertex indices
  400.   Element3 *pe;             // Element pointer
  401.   Element3 *pehd;           // Element head pointer
  402.   ElemList *pel;            // Element list pointer
  403.   ElemList *pelhd;          // Element list head pointer
  404.   Vertex3 *pv[4];           // Vertex pointers array
  405.  
  406.   ReadLine(efile);      // Read element section header
  407.  
  408.   for ( ; ; )
  409.   {
  410.     ReadLine(efile);    // Read element identifier
  411.  
  412.     if (sscanf(line_buff, "%hd %1s %hd %hd %hd %hd %1s",
  413.         &p_index, start, &ivtx[0], &ivtx[1], &ivtx[2],
  414.         &ivtx[3], end) == 7)
  415.     {
  416.       // Validate patch index
  417.       if (p_index >= patch_cnt)
  418.       {
  419.         sprintf(msg_buff,
  420.             "Entity file: %s\nElement # %u\nPatch index "
  421.             "error: %s", ent_buff, elem_cnt + 1,
  422.             line_buff);
  423.         ReportError(msg_buff);
  424.         status = FALSE;
  425.         break;
  426.       }
  427.  
  428.       // Validate vertex array indices
  429.       for (v_index = 0; v_index < 4; v_index++)
  430.       {
  431.         if (ivtx[v_index] >= vert_cnt)
  432.         {
  433.           sprintf(msg_buff,
  434.               "Entity file: %s\nElement # %u\nVertex index "
  435.               "error: %s", ent_buff, elem_cnt + 1,
  436.               line_buff);
  437.           ReportError(msg_buff);
  438.           status = FALSE;
  439.           break;
  440.         }
  441.       }
  442.  
  443.       if (status == FALSE)
  444.         break;
  445.  
  446.       // Get vertex pointers
  447.       for (v_index = 0; v_index < 4; v_index++)
  448.         pv[v_index] = pv_array[ivtx[v_index]];
  449.  
  450.       // Update patch element linked list
  451.       pe = new Element3(pv, pp_array[p_index]);
  452.       pehd = pp_array[p_index]->GetElementPtr();
  453.       pe->SetNext(pehd);
  454.       pp_array[p_index]->SetElementPtr(pe);
  455.       penv->num_elem++;
  456.       elem_cnt++;
  457.  
  458.       // Determine whether triangle or quadrilateral
  459.       if (ivtx[2] != ivtx[3])
  460.       {
  461.         nvert = 4;
  462.         pe->SetQuad();
  463.       }
  464.       else
  465.         nvert = 3;
  466.  
  467.       for (v_index = 0; v_index < nvert; v_index++)
  468.       {
  469.         // Update vertex element linked list
  470.         pelhd = pv[v_index]->GetElemListPtr();
  471.         pel = new ElemList(pe, pelhd);
  472.         pv[v_index]->SetElemListPtr(pel);
  473.       }
  474.     }
  475.     else
  476.       break;
  477.   }
  478.  
  479.   return status;
  480. }
  481.  
  482. void Parse::ReadTransform()
  483. {
  484.   double sx, sy, sz;    // Scaling parameters
  485.   double rx, ry, rz;    // Rotation parameters
  486.   double tx, ty, tz;    // Translation parameters
  487.  
  488.   // Read transformation vectors
  489.   ReadVector(ifile, &sx, &sy, &sz);
  490.   ReadVector(ifile, &rx, &ry, &rz);
  491.   ReadVector(ifile, &tx, &ty, &tz);
  492.  
  493.   // Convert rotation angles to radians
  494.   rx = DegToRad(rx);
  495.   ry = DegToRad(ry);
  496.   rz = DegToRad(rz);
  497.  
  498.   // Calculate vertex transformation matrix
  499.   tm.SetScale(sx, sy, sz);
  500.   tm.SetRotation(rx, ry, rz);
  501.   tm.SetTranslation(tx, ty, tz);
  502.   tm.BuildTransform();
  503. }
  504.  
  505. // Read vertex identifier
  506. Vertex3 *Parse::ReadVertex()
  507. {
  508.   double xval, yval, zval;      // Vertex coordinates
  509.  
  510.   if ((ReadVector( efile, &xval, &yval, &zval)) == TRUE)
  511.   {
  512.     Point3 *p3;
  513.     p3 = new Point3(xval,yval,zval);
  514.     return new Vertex3(*p3);
  515.   }
  516.   else
  517.     return NULL;
  518. }
  519.  
  520. // Read vector
  521. BOOL Parse::ReadVector( WinText &file, double *px, double
  522.     *py, double *pz )
  523. {
  524.   float x, y, z;                // Temporary variables
  525.   char start[2], end[2];        // Data separators
  526.  
  527.   ReadLine(file);       // Read vector
  528.  
  529.   if (sscanf(line_buff, "%1s %f %f %f %1s", start, &x, &y,
  530.       &z, end) == 5)
  531.   {
  532.     *px = x;
  533.     *py = y;
  534.     *pz = z;
  535.  
  536.     return TRUE;
  537.   }
  538.   else
  539.     return FALSE;
  540. }
  541.  
  542. // Transform entity into instance
  543. void Parse::TransformInstance( Instance *pinst )
  544. {
  545.   Element3 *pe;         // Element pointer
  546.   Patch3 *pp;           // Patch pointer
  547.   Surface3 *ps;         // Surface pointer
  548.   Vertex3 *pv;          // Vertex pointer
  549.  
  550.   // Transform vertex co-ordinates
  551.   pv = pinst->GetVertPtr();
  552.   while (pv != NULL)
  553.   {
  554.     tm.Transform(pv->GetPosnPtr());
  555.     pv = pv->GetNext();
  556.   }
  557.  
  558.   // Calculate patch attributes
  559.   ps = pinst->GetSurfPtr();
  560.   while (ps != NULL)
  561.   {
  562.     pp = ps->GetPatchPtr();
  563.     while (pp != NULL)
  564.     {
  565.       // Calculate element attributes
  566.       pe = pp->GetElementPtr();
  567.       while (pe != NULL)
  568.       {
  569.         pe->CalcArea();
  570.         pe->CalcNormal();
  571.         pe = pe->GetNext();
  572.       }
  573.  
  574.       pp->CalcArea();
  575.       pp->CalcCenter();
  576.       pp->CalcNormal();
  577.       pp = pp->GetNext();
  578.     }
  579.     ps = ps->GetNext();
  580.   }
  581.  
  582.   // Calculate vertex normals
  583.   pv = pinst->GetVertPtr();
  584.   while (pv != NULL)
  585.   {
  586.     pv->CalcNormal();
  587.     pv = pv->GetNext();
  588.   }
  589. }
  590.  
  591. // Read next line from file
  592. void Parse::ReadLine( WinText &file )
  593. {
  594.   for ( ; ; )
  595.   {
  596.     file.GetLine(line_buff, MaxLine);
  597.  
  598.     // Skip comment lines
  599.     if (strncmp(line_buff, CommentStr, strlen(CommentStr))
  600.         != 0)
  601.       break;
  602.   }
  603. }
  604.  
  605.